#include "cmd.h"

cli_cmd_list user_cmd_list;
void * cmd_ctrl_debug_info_switch(int argc, char **argv, int *ret_len);
void * cmd_help(int argc, char **argv, int *ret_len);
// cli_cmd_list cmd_register_list[] = {
//     {0, "help",        cmd_help,                   "print help info        "},
//     {0, "debug_level", cmd_ctrl_debug_info_switch, "modify debug info level"},
//     {0, "debug", cmd_ctrl_debug_info_switch, "modify debug info level"},
//     {0, NULL, NULL, NULL}
// };

static void cli_cmd_register_init() {
    register_cmd_func("help", cmd_help, "print help info");
    register_cmd_func("debug_level", cmd_ctrl_debug_info_switch, "modify debug info level");
    // for (int i = 0; cmd_register_list[i].cmd_name != NULL; i++) {
    //     LOG_DEBUG("register: cmd name=%s, help info=%s\n", cmd_register_list[i].cmd_name,
    //     cmd_register_list[i].help_info);
    //     register_cmd_func(cmd_register_list[i].cmd_name,
    //             cmd_register_list[i].func, cmd_register_list[i].help_info);
    // }
}

static void get_cmd_args(int *argc, char ***argv, char *msg, int length, int *cmd0_s) {
    int arg_num = 0;
    int prev_flag = 0; // 记录空格还是字符
    int cur_flag = 0; // 记录空格还是字符
    int f_index = 0; // 记录参数的第一个字符下标
    int l_index = 0; // 记录参数的最后一个字符下标
    int arg_index = 0;
    char **arg_c;
    char *tmp;
    int cmd0_f = 0;
    int need_argv = 0;
    LOG_DEBUG("[get argc]length = %d, msg = %s\n", length, msg);
    for (int i = 0; i < length; i++) {
        if (msg[i] == ' ') {
            cur_flag = 0;
        } else {
            cur_flag = 1;
        }
        if (prev_flag == 0 && cur_flag == 1) {
            arg_num++;
        }
        prev_flag = cur_flag;
    }
    prev_flag = 0;
    cur_flag = 0;
    arg_c = (char **)malloc(arg_num * sizeof(char *));
    for (int i = 0; i < length; i++) {
        need_argv = 0;
        if (msg[i] == ' ') {
            cur_flag = 0;
        } else {
            cur_flag = 1;
        }
        if (prev_flag == 0 && cur_flag == 1) {
            f_index = i;
        } else if (prev_flag == 1 && cur_flag == 0) {
            l_index = i - 1;
            need_argv = 1;
        } else if (i == length - 1 && cur_flag == 1) {
            l_index = i;
            need_argv = 1;
        }
        prev_flag = cur_flag;
        if (need_argv) {
            tmp = malloc(l_index - f_index + 1);
            mnet_memcpy(tmp, msg + f_index, l_index - f_index + 1);
            *(arg_c + arg_index++) = tmp;
            if (cmd0_f == 0) {
                *cmd0_s = l_index - f_index + 1;
                cmd0_f = 1;
            }
        }
    }
    *argc = arg_num;
    // LOG_DEBUG("[get argc]argc = %d\n", *argc);
    *argv = arg_c;
    free(msg);
}

void cli_cmd_list_init(cli_cmd_list *l) {
    l->cmd_name = NULL;
    l->func = NULL;
    l->help_info = NULL;
    // l->list = (nlist_node_t *)malloc(sizeof(nlist_node_t));
    nlist_node_init(&l->list);
    cli_cmd_register_init();
}

void register_cmd_func(char *cmd_name, CMD_FUNC func, char *help_info) {
    cli_cmd_list *new_list = (cli_cmd_list *)malloc(sizeof(cli_cmd_list));
    // LOG_ERROR("h_addr:%x, func name:%s, addr:%x\n", user_cmd_list.list, cmd_name, new_list->list);
    // LOG_ERROR("h_addr:%x, func name:%s, addr:%x\n", user_cmd_list, cmd_name, new_list);
    new_list->cmd_name = cmd_name;
    new_list->func = func;
    new_list->help_info = help_info;
    // LOG_DEBUG("cmd name:%s, help info:%s\n", new_list->cmd_name, new_list->help_info);
    nlist_node_init(&new_list->list);
    nlist_node_set_next(&user_cmd_list.list, &new_list->list);
}

void * exec_cmd_func(char *cmd_content, int length, int *ret_len) {
    int argc;
    int is_find = 0;
    char *ret = (void *)0;
    char **argv;
    int cmd0_size = 0;
    cli_cmd_list *cmd_stru;
    char *not_found_msg = malloc(CMD_NOT_FOUND_LEN);
    memcpy(not_found_msg, CMD_NOT_FOUND_MSG, CMD_NOT_FOUND_LEN);
    get_cmd_args(&argc, &argv, cmd_content, length, &cmd0_size);
    LOG_WARNNING("argc = %d\n", argc);
    if (argc == 0) return NULL;
    for (int i = 0; i < argc; i++)
        LOG_WARNNING("argv[%d] = %s\n", i, argv[i]);
    nlist_node_t *head_list = &user_cmd_list.list;
    while (!nlist_is_empty(head_list)) {
        head_list = head_list->next;
        if (head_list == &user_cmd_list.list) {
            break;
        }
        cmd_stru = mnet_get_list_entry(head_list, cli_cmd_list, list);
        if (mnet_memcmp(cmd_stru->cmd_name, argv[0], cmd0_size) == 0) {
            ret = cmd_stru->func(argc, argv, ret_len);
            is_find = 1;
            break;
        }
    }
    for (int i = 0; i < argc; i++) {
        free(argv[i]);
    }
    if (!is_find) {
        LOG_ERROR("cli cmd not found\n");
        ret = not_found_msg;
        *ret_len = CMD_NOT_FOUND_LEN;
    }
    return ret;
}


void * cmd_help(int argc, char **argv, int *ret_len) {
    mnet_printf("| cmd func name |       info          |\n");
    // for (int i = 0; cmd_register_list[i].cmd_name != NULL; i++) {
    //     mnet_printf("| %s | %s |\n", cmd_register_list[i].cmd_name, cmd_register_list[i].help_info);
    // }
    *ret_len = 6;
    char *msg = malloc(6);
    memcpy(msg, "123456", 6);
    return msg;
}

void * cmd_ctrl_debug_info_switch(int argc, char **argv, int *ret_len) {
    extern volatile LOG_LEVEL dbg_switch;
    if (memcmp(argv[1], "info", 4) == 0) {
        dbg_switch = LOG_LEVEL_INFO;
    } else if (memcmp(argv[1], "warn", 4) == 0) {
        dbg_switch = LOG_LEVEL_WARNNING;
    } else if (memcmp(argv[1], "error", 5) == 0) {
        dbg_switch = LOG_LEVEL_ERROR;
    } else if (memcmp(argv[1], "fatal", 5) == 0) {
        dbg_switch = LOG_LEVEL_FATAL;
    } else if (memcmp(argv[1], "debug", 5) == 0) {
        dbg_switch = LOG_LEVEL_DEBUG;
    } else {
        mnet_printf("err cmd!\n");
    }
    *ret_len = 0;
    return (void *)0;
}